/*
 * Copyright (c) 2022, yifengling0. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "atom.h"
#include "syslog.h"
#undef OK
#include "time.h"
#include <ESP32Time.h>
#define ATOM_NONE_STANDARDIO
#include "rtc.h"
#include "drv_rtc.h"

static ESP32Time esp32_rtc;

static void get_rtc_timestamp(RtcTime *tm_new)
{
    if (tm_new == NULL) {
        SYSLOG(LOG_ERR, "Null pointer provided\n");
        return;
    }

    // 获取当前时间
    time_t rawtime;
    struct tm* timeinfo;

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    if (timeinfo == NULL) {
        SYSLOG(LOG_ERR, "Failed to get localtime\n");
        return;
    }

    // 填充RtcTime结构体
    tm_new->tm_sec = timeinfo->tm_sec;
    tm_new->tm_min = timeinfo->tm_min;
    tm_new->tm_hour = timeinfo->tm_hour;
    tm_new->tm_mday = timeinfo->tm_mday;
    tm_new->tm_mon = timeinfo->tm_mon;    // tm_mon是从0开始的，需要加1
    tm_new->tm_year = timeinfo->tm_year; // tm_year是从1900开始的，需要加1900
    tm_new->tm_wday = timeinfo->tm_wday;
    tm_new->tm_yday = timeinfo->tm_yday;
    tm_new->tm_isdst = timeinfo->tm_isdst;
}

static int set_rtc_time_stamp(RtcTime* time_stamp)
{
    if (time_stamp == NULL) {
        return ATOM_ERR_CONTEXT; 
    }

    int year = time_stamp->tm_year + 1900; // Adjust year
    int month = time_stamp->tm_mon + 1;    // Adjust month (0-11 to 1-12)

  // 设置时间
    esp32_rtc.setTime(time_stamp->tm_sec, time_stamp->tm_min, time_stamp->tm_hour, time_stamp->tm_mday, month, year);

    return ATOM_OK; // Success
}


static RtcWakeAlarm _alarm = {0};

static void set_rtc_alarm(RtcWakeAlarm *alarm)
{
    memcpy(&_alarm, alarm, sizeof(RtcWakeAlarm));
    SYSLOG(LOG_ERR, "rtc alarm not implement!");
}

static void get_rtc_alarm(RtcWakeAlarm *alarm)
{
    memcpy(alarm, &_alarm, sizeof(RtcWakeAlarm));
}

static void rtc_wakeup_handler(union sigval sv) {
    RtcWakeUp* wakeup = (RtcWakeUp*)sv.sival_ptr;
    if (wakeup->callback) {
        wakeup->callback(wakeup);
    }
}


static void set_rtc_wakeup(RtcWakeUp *wakeup)
{
    SYSLOG(LOG_ERR, "rtc wakeup not implement!");
}

static int rtc_ioctl(FD fd, int function, void* arg)
{
    switch (function)
    {
    case RTC_CTRL_GET_DATETIME:
        get_rtc_timestamp((RtcTime*)arg);
        break;
    case RTC_CTRL_SET_DATETIME:
        if (set_rtc_time_stamp((RtcTime *)arg))
        {
            return NG;
        }
        break;
    case RTC_CTRL_GET_ALARM:
        set_rtc_alarm((RtcWakeAlarm *)arg);
        break;
    case RTC_CTRL_SET_ALARM:
        get_rtc_alarm((RtcWakeAlarm *)arg);
        break;
    case RTC_CTRL_SET_WAKEUP:
        set_rtc_wakeup((RtcWakeUp *)arg);
        break;
    }

    return OK;
}

static Esp32Rtc _rtc;

void Esp32RtcCreate(void)
{
    RtcCreate(&_rtc.Super, rtc_ioctl);
    SYSLOG(LOG_INFO, "rtc module initlized");
}